/**
 * Copyright 2019-2020 Huawei Technologies Co., Ltd
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "graph_optimizer/op_setter/op_setter.h"
#include "graph/compute_graph.h"
#include "graph/debug/ge_attr_define.h"
#include "common/aicore_util_attr_define.h"
#include "common/util/op_info_util.h"
#include "common/fe_utils.h"
#include "common/lxfusion_json_util.h"
#include "common/configuration.h"
#include "ops_store/ops_kernel_manager.h"

namespace fe {
using OpCalcInfoPtr = std::shared_ptr<OpCalcInfo>;

static const vector<string> LIST_OF_SUPPORT_L1_OP = {"Conv2D", "DepthwiseConv2D", "Deconvolution", "Pooling",
                                                     "FullyConnection", "AscendQuant", "ConcatV2D", "Eltwise", "Scale",
                                                     "BNInference"};

const std::map<string, string> OpSetter::attr_map_ = {{fe::STR_INPUT_MEM_CONTINUES, ge::ATTR_NAME_CONTINUOUS_INPUT},
                                                      {fe::STR_OUTPUT_MEM_CONTINUES, ge::ATTR_NAME_CONTINUOUS_OUTPUT}};

OpSetter::OpSetter(const std::string engine_name) : engine_name_(engine_name) {}
OpSetter::~OpSetter() {}

const std::map<SlicePattern, FillupSliceInfoPtr> OpSetter::split_info_map_ = {
        {ELEMENT_WISE, std::make_shared<FillupSliceInfo>(FillupElemwiseSliceInfo)},
        {ELEMENT_WISE_BROADCAST, std::make_shared<FillupSliceInfo>(FillupElemwiseBroadcastSliceInfo)},
        {BROADCAST, std::make_shared<FillupSliceInfo>(FillupBroadcastSliceInfo)},
        {SLIDING_WINDOW, std::make_shared<FillupSliceInfo>(FillupSlidingWindowSliceInfo)},
        {SLIDING_WINDOW_DECONV, std::make_shared<FillupSliceInfo>(FillupSlidingWindowDeconvSliceInfo)},
        {CUBE_MATMUL, std::make_shared<FillupSliceInfo>(FillupCubeMatmulSliceInfo)},
        {SLICE_PATTERN_REDUCE, std::make_shared<FillupSliceInfo>(FillupReduceSliceInfo)},
        {SLICE_PATTERN_RESIZE, std::make_shared<FillupSliceInfo>(FillupResizeSliceInfo)},
        {SLICE_PATTERN_SCATTER, std::make_shared<FillupSliceInfo>(FillupScatterSliceInfo)},
        {SLICE_PATTERN_SEGMENT, std::make_shared<FillupSliceInfo>(FillupSegmentSliceInfo)},
};

Status OpSetter::SetOpInfo(ge::ComputeGraph& graph) {
  for (auto& node : graph.GetAllNodes()) {
    Status result = SetOpInfoByNode(node);
    if (result != SUCCESS) {
      return result;
    }
  }
  return SUCCESS;
}

Status OpSetter::SetOpInfoByNode(ge::NodePtr node_ptr) {
  // 1. check the node_ptr and the op_desc_ptr
  FE_CHECK_NOTNULL(node_ptr);
  ge::OpDescPtr op_desc_ptr = node_ptr->GetOpDesc();
  FE_CHECK_NOTNULL(op_desc_ptr);

  // 2. check the imply_type
  string op_name = op_desc_ptr->GetName();
  string op_type = op_desc_ptr->GetType();
  int imply_type = -1;
  if (!ge::AttrUtils::GetInt(op_desc_ptr, FE_IMPLY_TYPE, imply_type)) {
    FE_LOGD("Op[name=%s,type=%s]: Get the attribute FE_IMPLY_TYPE not success.", op_name.c_str(), op_type.c_str());
    return SUCCESS;
  }

  // 3. get the op_kernel_info_ptr by op_impl_type and op_type
  OpImplType op_impl_type = (OpImplType)imply_type;
  OpKernelInfoPtr op_kernel_info_ptr =
          OpsKernelManager::Instance(engine_name_).GetOpKernelInfoByOpType(op_impl_type, op_desc_ptr->GetType());
  if (op_kernel_info_ptr == nullptr) {
    FE_LOGW("Op[name=%s,type=%s]: get the op kernel info failed.", op_name.c_str(), op_type.c_str());
    return SUCCESS;
  }
  FE_CHECK_NOTNULL(op_kernel_info_ptr);

  // 4. set the attributes of the op
  for (auto& it : attr_map_) {
    if (SetOpDescAttr(op_kernel_info_ptr, it.first, it.second, op_desc_ptr) != SUCCESS) {
      REPORT_FE_ERROR(
          "[GraphOptJdgInst][SetOpInfo][SetOpInfo] Op[name=%s,type=%s]: get the attribute [%s] from the op "
          "kernel info, and set the attribute [%s] failed!",
          op_name.c_str(), op_type.c_str(), it.first.c_str(), it.second.c_str());
      return FAILED;
    }
  }

  // 5. set slice info for each node of graph
  if (SUCCESS != SetOpSlicePatternInfoByNode(op_desc_ptr, op_kernel_info_ptr)) {
    FE_LOGW("Op[name=%s,type=%s]: set the slice info for node failed!", op_name.c_str(), op_type.c_str());
  }
  return SUCCESS;
}

Status OpSetter::SetOpDescAttr(const OpKernelInfoPtr& op_kernel_info_ptr, const std::string& attr_name,
                               const std::string& ge_attr_name, ge::OpDescPtr op_desc_ptr) {
  string op_name = op_desc_ptr->GetName();
  string op_type = op_desc_ptr->GetType();
  bool value = false;

  if (attr_name == STR_INPUT_MEM_CONTINUES) {
    value = op_kernel_info_ptr->GetInputMemContinuesFlag();
  } else if (attr_name == STR_OUTPUT_MEM_CONTINUES) {
    value = op_kernel_info_ptr->GetOutputMemContinuesFlag();
  } else {
    REPORT_FE_ERROR("[GraphOptJdgInst][SetOpInfo][SetOpDescAttr] the attribute [%s] can not get from op kernel.",
                    attr_name.c_str());
    return FAILED;
  }
  FE_LOGD("Op[name=%s,type=%s]: get the attribute [%s] success, value is %d", op_name.c_str(), op_type.c_str(),
          attr_name.c_str(), value);

  if (!ge::AttrUtils::SetBool(op_desc_ptr, ge_attr_name, value)) {
    REPORT_FE_ERROR("[GraphOptJdgInst][SetOpInfo][SetOpDescAttr] Op[name=%s,type=%s]: set the attribute [%s] failed.",
                    op_name.c_str(), op_type.c_str(),
            ge_attr_name.c_str());
    return FAILED;
  }
  FE_LOGD("Op[name=%s,type=%s]: set the attribute [%s] success.", op_name.c_str(), op_type.c_str(),
          ge_attr_name.c_str());
  return SUCCESS;
}

void OpSetter::SetInputSplitInfo(AxisSplitMap& axis_split_map, const int8_t& input_index, const int8_t& input_axis) {
  InputSplitInfo input_split_info;
  if (!input_split_info.Initialize()) {
    REPORT_FE_ERROR("[GraphOptJdgInst][SetOpInfo][SetInSplitInfo] input_split_info initialize failed");
    return;
  }
  input_split_info.SetIndex(input_index);
  std::vector<int64_t> input_vec_first_tensor = {input_axis};
  input_split_info.SetAxis(input_vec_first_tensor);
  axis_split_map.AddInputSplitInfo(input_split_info);
}

void OpSetter::SetInputReduceInfo(AxisReduceMap& axis_reduce_map, const int8_t& input_index, const int8_t& input_axis) {
  InputReduceInfo input_reduce_info;
  if (!input_reduce_info.Initialize()) {
    REPORT_FE_ERROR("[GraphOptJdgInst][SetOpInfo][SetInRduInfo] input_reduce_info initialize failed");
    return;
  }
  input_reduce_info.SetIndex(input_index);
  std::vector<int64_t> input_vec_first_tensor = {input_axis};
  input_reduce_info.SetAxis(input_vec_first_tensor);
  axis_reduce_map.AddInputReduceInfo(input_reduce_info);
}

void OpSetter::SetOutputSplitInfo(AxisSplitMap& axis_split_map, const int8_t& output_index, const int8_t& output_axis) {
  OutputSplitInfo output_split_info;
  if (!output_split_info.Initialize()) {
    REPORT_FE_ERROR("[GraphOptJdgInst][SetOpInfo][SetOutSplitInfo] output_split_info initialize failed");
    return;
  }
  output_split_info.SetIndex(output_index);
  std::vector<int64_t> output_vec = {output_axis};
  output_split_info.SetAxis(output_vec);
  axis_split_map.AddOutputSplitInfo(output_split_info);
}

void OpSetter::SetOutputReduceInfo(AxisReduceMap& axis_reduce_map, const int8_t& output_index,
                                   const OpReduceType& reduce_type, const bool& is_atomic) {
  OutputReduceInfo output_reduce_info;
  if (!output_reduce_info.Initialize()) {
    REPORT_FE_ERROR("[GraphOptJdgInst][SetOpInfo][SetOutRdcInfo] output_reduce_info initialize failed");
    return;
  }
  output_reduce_info.SetIndex(output_index);
  output_reduce_info.SetReduceType(reduce_type);
  output_reduce_info.SetIsAtomic(is_atomic);
  axis_reduce_map.AddOutputReduceInfo(output_reduce_info);
}

/*
 *  @ingroup fe
 *  @brief   Set the slice information based on the input and output indexes/axes.
 *  @param   [in|out] input and output indexes/axes | slice info
 *  @return  SUCCESS or FAILED
 */
void OpSetter::SetMultiAxisSplitMap(AxisSplitMap& axis_split_map,
                                              const int8_t& first_index, const int8_t& first_axis,
                                              const int8_t& output_index, const int8_t& output_axis,
                                              const int8_t second_index, const int8_t second_axis) {
  SetInputSplitInfo(axis_split_map, first_index, first_axis);

  if (second_index > -1 && second_axis > -1) {
    SetInputSplitInfo(axis_split_map, second_index, second_axis);
  }

  SetOutputSplitInfo(axis_split_map, output_index, output_axis);
}

Status OpSetter::CheckElemwiseInputAndOutputNum(ge::OpDescPtr op_desc_ptr, bool &has_scalar,
                                                          size_t &dim_size, ge::Format &op_output_format) {
  auto op_input_desc_list = op_desc_ptr->GetAllInputsDescPtr();
  auto op_output_desc_list = op_desc_ptr->GetAllOutputsDescPtr();
  if (op_output_desc_list.size() != 1 && !has_scalar) {
    FE_LOGW("Node [%s] has %d output, not equal to one.", op_desc_ptr->GetName().c_str(), op_output_desc_list.size());
    return FAILED;
  }
  if (op_input_desc_list.empty()) {
    FE_LOGW("Node [%s] do not have any input.", op_desc_ptr->GetName().c_str());
    return FAILED;
  }
  if (dim_size == 0) {
    FE_LOGW("Node [%s]'s output has %d output dim size, cannot set split info.",
            op_desc_ptr->GetName().c_str(), dim_size);
    return FAILED;
  }
  // dim number of shape and format of all inputs and outputs should be the same.
  for (uint32_t index = 0; index < op_input_desc_list.size(); index++) {
    auto op_input_desc_primary_format =
        static_cast<ge::Format>(ge::GetPrimaryFormat(op_input_desc_list.at(index)->GetFormat()));
    if (op_input_desc_primary_format != op_output_format) {
      FE_LOGW("Node [%s]'s input format [%s] not equal to output [%s], cannot set split info.",
              op_desc_ptr->GetName().c_str(), ConstFormatToStr(op_input_desc_primary_format).c_str(),
              FormatToStr(op_output_format).c_str());
      return FAILED;
    }
    if ((op_input_desc_list.at(index)->GetShape().GetDimNum() != 0 || !has_scalar) &&
        op_input_desc_list.at(index)->GetShape().GetDimNum() != dim_size) {
      FE_LOGW("Node [%s]'s input dim size [%d] not equal to output [%d], cannot set split info.",
              op_desc_ptr->GetName().c_str(), op_input_desc_list.at(index)->GetShape().GetDimNum(), dim_size);
      return FAILED;
    }
  }
  FE_LOGD("check input and output info for node[%s] success.", op_desc_ptr->GetName().c_str());
  return SUCCESS;
}

/*
 *  @ingroup fe
 *  @brief   Set the slice information corresponding to the elemwise based on the node information.
 *  @param   [in|out] node & has scalar or not | slice info
 *  @return  SUCCESS or FAILED
 */
Status OpSetter::SetElemWiseSliceInfo(ge::OpDescPtr op_desc_ptr,
                                                std::vector<AxisSplitMap>& axis_split_maps, bool has_scalar) {
  auto op_input_desc_list = op_desc_ptr->GetAllInputsDescPtr();
  auto op_output_desc_list = op_desc_ptr->GetAllOutputsDescPtr();
  size_t dim_size = op_output_desc_list.at(0)->GetShape().GetDimNum();
  ge::Format op_output_format = static_cast<ge::Format>(ge::GetPrimaryFormat(op_output_desc_list.at(0)->GetFormat()));
  // check input and output info for node
  Status ret = CheckElemwiseInputAndOutputNum(op_desc_ptr, has_scalar, dim_size, op_output_format);
  if (ret != SUCCESS) {
    FE_LOGW("Check node[%s]'s input info or output info failed, cannot set slice info.",
            op_desc_ptr->GetName().c_str());
    return FAILED;
  }
  // do not set slice info for 5hd's last one dimension
  size_t split_size = dim_size;
  bool isFiveDimension = op_output_format == ge::FORMAT_NC1HWC0 || op_output_format == ge::FORMAT_NHWC1C0 ||
                         op_output_format == ge::FORMAT_C1HWNC0 || op_output_format == ge::FORMAT_NC1HWC0_C04;
  if (isFiveDimension) {
    split_size -= 1;
  }
  // do not set slice info for fragz's last two dimension
  bool isFragzDimension = op_output_format == ge::FORMAT_FRACTAL_NZ || op_output_format == ge::FORMAT_FRACTAL_Z ||
                          op_output_format == ge::FORMAT_FRACTAL_Z_C04;
  if (isFragzDimension) {
    split_size -= 2;
  }
  if (split_size <= 0) {
    FE_LOGW("Node [%s]'s split size %d less than zero, cannot set split info.", op_desc_ptr->GetName().c_str(),
            split_size);
    return FAILED;
  }
  // set slice info for every input and output of elemwise node, each input and output of the elem node can be sliced
  // except 5hd's last one dimension and fragz's last two dimension
  for (uint32_t axis = 0; axis < split_size; axis++) {
    AxisSplitMap axis_split_map;
    if (!axis_split_map.Initialize()) {
      REPORT_FE_ERROR("[GraphOptJdgInst][SetOpInfo][SetElemWiseSliceInfo] axis_split_map initialize failed");
      return FAILED;
    }
    for (uint32_t index = 0; index < op_input_desc_list.size(); index++) {
      if (op_input_desc_list.at(index)->GetShape().GetDimNum() == 0) {
        FE_LOGD("Node [%s]'s %d input dim size is zero, cannot set split info.", op_desc_ptr->GetName().c_str(), index);
        continue;
      }
      SetInputSplitInfo(axis_split_map, index, axis);
    }
    for (uint32_t index = 0; index < op_output_desc_list.size(); index++) {
      if (op_output_desc_list.at(index)->GetShape().GetDimNum() == 0) {
        FE_LOGD("Node [%s]'s %d output dim size is zero, cannot set split info.",
                op_desc_ptr->GetName().c_str(), index);
        continue;
      }
      SetOutputSplitInfo(axis_split_map, index, axis);
    }
    axis_split_maps.push_back(axis_split_map);
  }
  return SUCCESS;
}
/*
 *  @ingroup fe
 *  @brief   Set the slice information corresponding to the slidingwindow based on the node information.
 *  @param   [in|out] node | slice info
 *  @return  SUCCESS or FAILED
 */
Status OpSetter::SetSlidingWindowSliceInfo(ge::OpDescPtr op_desc_ptr, std::vector<AxisSplitMap>& axis_split_maps) {
  AxisSplitMap axis_split_map_cut_n;
  if (!axis_split_map_cut_n.Initialize()) {
    REPORT_FE_ERROR("[GraphOptJdgInst][SetOpInfo][SetSlidWinSliceInfo] axis_split_map_cut_n initialize failed");
    return FAILED;
  }
  SetMultiAxisSplitMap(axis_split_map_cut_n, 0, 0, 0, 0);
  axis_split_maps.push_back(axis_split_map_cut_n);

  AxisSplitMap axis_split_map_cut_h;
  if (!axis_split_map_cut_h.Initialize()) {
    REPORT_FE_ERROR("[GraphOptJdgInst][SetOpInfo][SetSlidWinSliceInfo] axis_split_map_cut_h initialize failed");
    return FAILED;
  }
  SetMultiAxisSplitMap(axis_split_map_cut_h, 0, 2, 0, 2);
  axis_split_maps.push_back(axis_split_map_cut_h);

  AxisSplitMap axis_split_map_cut_w;
  if (!axis_split_map_cut_w.Initialize()) {
    REPORT_FE_ERROR("[GraphOptJdgInst][SetOpInfo][SetSlidWinSliceInfo] axis_split_map_cut_w initialize failed");
    return FAILED;
  }
  SetMultiAxisSplitMap(axis_split_map_cut_w, 0, 3, 0, 3);
  axis_split_maps.push_back(axis_split_map_cut_w);

  AxisSplitMap axis_split_map_cut_cout;
  if (!axis_split_map_cut_cout.Initialize()) {
    REPORT_FE_ERROR("[GraphOptJdgInst][SetOpInfo][SetSlidWinSliceInfo] axis_split_map_cut_cout initialize failed");
    return FAILED;
  }
  SetMultiAxisSplitMap(axis_split_map_cut_cout, 1, 1, 0, 1);
  axis_split_maps.push_back(axis_split_map_cut_cout);

  return SUCCESS;
}
/*
 *  @ingroup fe
 *  @brief   Set the slice information corresponding to the slidingwindowdeconv based on the node information.
 *  @param   [in|out] node | slice info
 *  @return  SUCCESS or FAILED
 */
Status OpSetter::SetSlidingWindowDeconvSliceInfo(ge::OpDescPtr op_desc_ptr,
                                                 std::vector<AxisSplitMap>& axis_split_maps) {
  AxisSplitMap axis_split_map_cut_n;
  if (!axis_split_map_cut_n.Initialize()) {
    REPORT_FE_ERROR("[GraphOptJdgInst][SetOpInfo][SetSlidWinDeconvSliceInfo] axis_split_map_cut_n initialize failed");
    return FAILED;
  }
  SetMultiAxisSplitMap(axis_split_map_cut_n, 0, 0, 0, 0);
  axis_split_maps.push_back(axis_split_map_cut_n);

  AxisSplitMap axis_split_map_cut_h;
  if (!axis_split_map_cut_h.Initialize()) {
    REPORT_FE_ERROR("[GraphOptJdgInst][SetOpInfo][SetSlidWinDeconvSliceInfo] axis_split_map_cut_h initialize failed");
    return FAILED;
  }
  SetMultiAxisSplitMap(axis_split_map_cut_h, 0, 2, 0, 2);
  axis_split_maps.push_back(axis_split_map_cut_h);

  AxisSplitMap axis_split_map_cut_w;
  if (!axis_split_map_cut_w.Initialize()) {
    REPORT_FE_ERROR("[GraphOptJdgInst][SetOpInfo][SetSlidWinDeconvSliceInfo] axis_split_map_cut_w initialize failed");
    return FAILED;
  }
  SetMultiAxisSplitMap(axis_split_map_cut_w, 0, 3, 0, 3);
  axis_split_maps.push_back(axis_split_map_cut_w);

  AxisSplitMap axis_split_map_cut_cout;
  if (!axis_split_map_cut_cout.Initialize()) {
    REPORT_FE_ERROR("[GraphOptJdgInst][SetOpInfo][SetSlidWinDeconvSliceInfo] axis_split_map_cut_cout initialize \
                    failed");
    return FAILED;
  }
  SetMultiAxisSplitMap(axis_split_map_cut_cout, 1, 1, 0, 1);
  axis_split_maps.push_back(axis_split_map_cut_cout);

  FE_LOGI("Not support to set min_tbe_l1_space info yet.");
  return SUCCESS;
}
/*
 *  @ingroup fe
 *  @brief   Set the slice information corresponding to the cube matmul based on the node information.
 *  @param   [in|out] node | slice info
 *  @return  SUCCESS or FAILED
 */
Status OpSetter::SetCubeMatmulSliceInfo(ge::OpDescPtr op_desc_ptr, std::vector<AxisSplitMap>& axis_split_maps) {
  auto input_format = static_cast<ge::Format>(ge::GetPrimaryFormat(op_desc_ptr->GetInputDescPtr(0)->GetFormat()));
  if (input_format == ge::FORMAT_NC1HWC0) {
    AxisSplitMap axis_split_map_cut_m;
    if (!axis_split_map_cut_m.Initialize()) {
      REPORT_FE_ERROR("[GraphOptJdgInst][SetOpInfo][SetCubeMulSliceInfo] axis_split_map_cut_m initialize failed");
      return FAILED;
    }
    SetMultiAxisSplitMap(axis_split_map_cut_m, 0, 0, 0, 0, -1, -1);
    AxisSplitMap axis_split_map_cut_n;
    if (!axis_split_map_cut_n.Initialize()) {
      REPORT_FE_ERROR("[GraphOptJdgInst][SetOpInfo][SetCubeMulSliceInfo] axis_split_map_cut_n initialize failed");
      return FAILED;
    }
    SetMultiAxisSplitMap(axis_split_map_cut_n, 1, 1, 0, 0, -1, -1);
    axis_split_maps.push_back(axis_split_map_cut_m);
    axis_split_maps.push_back(axis_split_map_cut_n);
  } else if (input_format == ge::FORMAT_FRACTAL_NZ) {
    AxisSplitMap axis_split_map_cut_m;
    if (!axis_split_map_cut_m.Initialize()) {
      REPORT_FE_ERROR("[GraphOptJdgInst][SetOpInfo][SetCubeMulSliceInfo] axis_split_map_cut_m initialize failed");
      return FAILED;
    }
    SetMultiAxisSplitMap(axis_split_map_cut_m, 0, 1, 0, 0, -1, -1);
    AxisSplitMap axis_split_map_cut_n;
    if (!axis_split_map_cut_n.Initialize()) {
      REPORT_FE_ERROR("[GraphOptJdgInst][SetOpInfo][SetCubeMulSliceInfo] axis_split_map_cut_n initialize failed");
      return FAILED;
    }
    SetMultiAxisSplitMap(axis_split_map_cut_n, 1, 0, 0, 0, -1, -1);
    axis_split_maps.push_back(axis_split_map_cut_m);
    axis_split_maps.push_back(axis_split_map_cut_n);

  } else {
    FE_LOGD("Cube-matmul node[%s] not supported cut format[%s]", op_desc_ptr->GetName().c_str(),
            ge::TypeUtils::FormatToSerialString(input_format).c_str());
  }
  return SUCCESS;
}
/*
 *  @ingroup fe
 *  @brief   Set the slice information corresponding to the reduce based on the node information.
 *  @param   [in|out] node | slice info
 *  @return  SUCCESS or FAILED
 */
Status OpSetter::SetReduceSliceInfo(ge::OpDescPtr op_desc_ptr, std::vector<AxisSplitMap>& axis_split_maps) {
  std::vector<int64_t> axes_vec;
  (void)ge::AttrUtils::GetListInt(op_desc_ptr, "axes", axes_vec);
  auto op_input_desc_list = op_desc_ptr->GetAllInputsDescPtr();
  auto op_output_desc_list = op_desc_ptr->GetAllOutputsDescPtr();
  // check input and output info for reduce node
  if (op_input_desc_list.size() < 1) {
    FE_LOGW("Node [%s] has %d input, less than one.", op_desc_ptr->GetName().c_str(), op_input_desc_list.size());
    return FAILED;
  }
  if (op_output_desc_list.size() != 1) {
    FE_LOGW("Node [%s] has %d output, not equal to one.", op_desc_ptr->GetName().c_str(), op_output_desc_list.size());
    return FAILED;
  }
  auto op_output_primary_format = static_cast<ge::Format>(ge::GetPrimaryFormat(op_output_desc_list.at(0)->GetFormat()));
  size_t dim_size = op_output_desc_list.at(0)->GetShape().GetDimNum();
  if (dim_size <= 0) {
    FE_LOGW("Node [%s]'s output has %d output dim size, cannot set split info.", op_desc_ptr->GetName().c_str(),
            dim_size);
    return FAILED;
  }
  // do not set slice info for reduce axes
  for (uint32_t index = 0; index < op_input_desc_list.size(); index++) {
    if (std::find(axes_vec.begin(), axes_vec.end(), index) != axes_vec.end()) {
      continue;
    }

    auto op_input_primary_format =
        static_cast<ge::Format>(ge::GetPrimaryFormat(op_input_desc_list.at(index)->GetFormat()));
    if (op_input_primary_format != op_output_primary_format) {
      FE_LOGW("Node [%s]'s input format [%s] not equal to output [%s], cannot set split info.",
              op_desc_ptr->GetName().c_str(), ConstFormatToStr(op_input_primary_format).c_str(),
              FormatToStr(op_output_primary_format).c_str());
      return FAILED;
    }
    if (op_input_desc_list.at(index)->GetShape().GetDimNum() != dim_size) {
      FE_LOGW("Node [%s]'s input dim size [%d] not equal to output [%d], cannot set split info.",
              op_desc_ptr->GetName().c_str(), op_input_desc_list.at(index)->GetShape().GetDimNum(), dim_size);
      return FAILED;
    }
  }
  for (uint32_t dim_num = 0; dim_num < dim_size; dim_num++) {
    AxisSplitMap axis_split_map;
    if (!axis_split_map.Initialize()) {
      REPORT_FE_ERROR("[GraphOptJdgInst][SetOpInfo][SetRdcSliceInfo] axis_split_map initialize failed");
      return FAILED;
    }
    if (std::find(axes_vec.begin(), axes_vec.end(), dim_num) != axes_vec.end()) {
      continue;
    }
    for (uint32_t index = 0; index < op_input_desc_list.size(); index++) {
      SetInputSplitInfo(axis_split_map, index, dim_num);
    }
    SetOutputSplitInfo(axis_split_map, 0, dim_num);
    axis_split_maps.push_back(axis_split_map);
  }
  return SUCCESS;
}

/*
 *  @ingroup fe
 *  @brief   Set the slice information for the node whose SlicePattern is Elemwise in the ops info config.
 *  @param   [in|out] node | slice info
 *  @return  SUCCESS or FAILED
 */
Status OpSetter::FillupElemwiseSliceInfo(ge::OpDescPtr op_desc_ptr, OpCalcInfo &op_calc_info) {
  FE_LOGD("Start to set node[%s]'s slice pattern as: elemwise.", op_desc_ptr->GetName().c_str());
  std::vector<AxisSplitMap> axis_split_maps;
  Status ret = SetElemWiseSliceInfo(op_desc_ptr, axis_split_maps, false);
  if (ret != SUCCESS) {
    FE_LOGD("Parse op slice info for node[%s] not matched, do not set slice info.", op_desc_ptr->GetName().c_str());
    return SUCCESS;
  }
  op_calc_info.SetAxisSplitMaps(axis_split_maps);
  return SUCCESS;
}

/*
 *  @ingroup fe
 *  @brief   Set the slice information for the node whose SlicePattern is ElemwiseBroadcast in the ops info config.
 *  @param   [in|out] node | slice info
 *  @return  SUCCESS or FAILED
 */
Status OpSetter::FillupElemwiseBroadcastSliceInfo(ge::OpDescPtr op_desc_ptr, OpCalcInfo &op_calc_info) {
  // slice info of elemwise-broadcast is the same as elemwise by now
  FE_LOGD("Start to set node[%s]'s slice pattern as: elemwise-broadcast.", op_desc_ptr->GetName().c_str());
  std::vector<AxisSplitMap> axis_split_maps;
  Status ret = SetElemWiseSliceInfo(op_desc_ptr, axis_split_maps, true);
  if (ret != SUCCESS) {
    FE_LOGD("Parse op slice info for node[%s] not matched, do not set slice info.", op_desc_ptr->GetName().c_str());
    return SUCCESS;
  }
  op_calc_info.SetAxisSplitMaps(axis_split_maps);
  return ret;
}

/*
 *  @ingroup fe
 *  @brief   Set the slice information for the node whose SlicePattern is Broadcast in the ops info config.
 *  @param   [in|out] node | slice info
 *  @return  SUCCESS or FAILED
 */
Status OpSetter::FillupBroadcastSliceInfo(ge::OpDescPtr op_desc_ptr, OpCalcInfo &op_calc_info) {
  // slice info of broadcast is the same as elemwise by now
  FE_LOGD("Start to set node[%s]'s slice pattern as: broadcast.", op_desc_ptr->GetName().c_str());
  std::vector<AxisSplitMap> axis_split_maps;
  Status ret = SetElemWiseSliceInfo(op_desc_ptr, axis_split_maps, false);
  if (ret != SUCCESS) {
    FE_LOGD("Parse op slice info for node[%s] not matched, do not set slice info.", op_desc_ptr->GetName().c_str());
    return SUCCESS;
  }
  op_calc_info.SetAxisSplitMaps(axis_split_maps);
  return ret;
}

/*
 *  @ingroup fe
 *  @brief   Set the slice information for the node whose SlicePattern is SlidingWindow in the ops info config.
 *  @param   [in|out] node | slice info
 *  @return  SUCCESS or FAILED
 */
Status OpSetter::FillupSlidingWindowSliceInfo(ge::OpDescPtr op_desc_ptr, OpCalcInfo &op_calc_info) {
  // In sliding-window, the slice information is fixed and must be in the following format:
  FE_LOGD("Start to set node[%s]'s slice pattern as: sliding-window.", op_desc_ptr->GetName().c_str());
  std::vector<AxisSplitMap> axis_split_maps;
  Status ret = SetSlidingWindowSliceInfo(op_desc_ptr, axis_split_maps);
  if (ret != SUCCESS) {
    FE_LOGD("Parse op slice info for node[%s] not matched, do not set slice info.", op_desc_ptr->GetName().c_str());
    return SUCCESS;
  }
  op_calc_info.SetAxisSplitMaps(axis_split_maps);
  return SUCCESS;
}

/*
 *  @ingroup fe
 *  @brief   Set the slice information for the node whose SlicePattern is SlidingWindowDeconv in the ops info config.
 *  @param   [in|out] node | slice info
 *  @return  SUCCESS or FAILED
 */
Status OpSetter::FillupSlidingWindowDeconvSliceInfo(ge::OpDescPtr op_desc_ptr, OpCalcInfo &op_calc_info) {
  // slice info of liding-window-deconv is the same as liding-window by now
  FE_LOGD("Start to set node[%s]'s slice pattern as: sliding-window-deconv.", op_desc_ptr->GetName().c_str());
  std::vector<AxisSplitMap> axis_split_maps;
  Status ret = SetSlidingWindowDeconvSliceInfo(op_desc_ptr, axis_split_maps);
  if (ret != SUCCESS) {
    FE_LOGD("Parse op slice info for node[%s] not matched, do not set slice info.", op_desc_ptr->GetName().c_str());
    return SUCCESS;
  }
  op_calc_info.SetAxisSplitMaps(axis_split_maps);
  return SUCCESS;
}

/*
 *  @ingroup fe
 *  @brief   Set the slice information for the node whose SlicePattern is CubeMatmul in the ops info config.
 *  @param   [in|out] node | slice info
 *  @return  SUCCESS or FAILED
 */
Status OpSetter::FillupCubeMatmulSliceInfo(ge::OpDescPtr op_desc_ptr, OpCalcInfo &op_calc_info) {
  // In cube-matmul, the slice information is fixed and must be in the following format:
  FE_LOGD("Start to set node[%s]'s slice pattern as: cube-matmul.", op_desc_ptr->GetName().c_str());
  std::vector<AxisSplitMap> axis_split_maps;
  std::vector<AxisReduceMap> axis_reduce_maps;
  Status ret = SetCubeMatmulSliceInfo(op_desc_ptr, axis_split_maps);
  if (ret != SUCCESS) {
    FE_LOGD("Parse op slice info for node[%s] not matched, do not set slice info.", op_desc_ptr->GetName().c_str());
    return SUCCESS;
  }
  // cube matmul node should have more than 2 inputs
  if (op_desc_ptr->GetInputsSize() > 2) {
    FE_LOGD("Node[%s] has bias input, not support cut k axis.", op_desc_ptr->GetName().c_str());
  } else {
    auto input_format = static_cast<ge::Format>(ge::GetPrimaryFormat(op_desc_ptr->GetInputDescPtr(0)->GetFormat()));
    AxisReduceMap axis_reduce_map_cut;
    if (!axis_reduce_map_cut.Initialize()) {
      REPORT_FE_ERROR("[GraphOptJdgInst][SetOpInfo][FillupCubeMulSliceInfo] Failed to initialize reduce map.");
      return FAILED;
    }

    if (input_format == ge::FORMAT_NC1HWC0) {
      SetInputReduceInfo(axis_reduce_map_cut, 0, 1);
      SetInputReduceInfo(axis_reduce_map_cut, 1, 0);
      SetOutputReduceInfo(axis_reduce_map_cut, 0, REDUCE_ADD, false);
    } else if (input_format == ge::FORMAT_FRACTAL_NZ) {
      SetInputReduceInfo(axis_reduce_map_cut, 0, 0);
      SetInputReduceInfo(axis_reduce_map_cut, 1, 1);
      SetOutputReduceInfo(axis_reduce_map_cut, 0, REDUCE_ADD, false);
    } else {
      FE_LOGD("Cube-matmul node[%s] not supported cut format[%s]", op_desc_ptr->GetName().c_str(),
              ge::TypeUtils::FormatToSerialString(input_format).c_str());
    }
    axis_reduce_maps.push_back(axis_reduce_map_cut);
  }
  op_calc_info.SetAxisSplitMaps(axis_split_maps);
  op_calc_info.SetAxisReduceMaps(axis_reduce_maps);
  return SUCCESS;
}

/*
 *  @ingroup fe
 *  @brief   Set the slice information for the node whose SlicePattern is Reduce in the ops info config.
 *  @param   [in|out] node | slice info
 *  @return  SUCCESS or FAILED
 */
Status OpSetter::FillupReduceSliceInfo(ge::OpDescPtr op_desc_ptr, OpCalcInfo &op_calc_info) {
  FE_LOGD("Start to set node[%s]'s slice pattern as: reduce.", op_desc_ptr->GetName().c_str());
  std::vector<AxisSplitMap> axis_split_maps;
  Status ret = SetReduceSliceInfo(op_desc_ptr, axis_split_maps);
  if (ret != SUCCESS) {
    FE_LOGD("Parse op slice info for node[%s] not matched, do not set slice info.", op_desc_ptr->GetName().c_str());
    return SUCCESS;
  }
  op_calc_info.SetAxisSplitMaps(axis_split_maps);
  return SUCCESS;
}

/*
 *  @ingroup fe
 *  @brief   Set the slice information for the node whose SlicePattern is resize in the ops info config.
 *  @param   [in|out] node | slice info
 *  @return  SUCCESS or FAILED
 */
Status OpSetter::FillupResizeSliceInfo(ge::OpDescPtr op_desc_ptr, OpCalcInfo &op_calc_info) {
  FE_LOGI("Not support this slice pattern yet.");
  return SUCCESS;
}

/*
 *  @ingroup fe
 *  @brief   Set the slice information for the node whose SlicePattern is scatter in the ops info config.
 *  @param   [in|out] node | slice info
 *  @return  SUCCESS or FAILED
 */
Status OpSetter::FillupScatterSliceInfo(ge::OpDescPtr op_desc_ptr, OpCalcInfo &op_calc_info) {
  FE_LOGI("Not support this slice pattern yet.");
  return SUCCESS;
}

/*
 *  @ingroup fe
 *  @brief   Set the slice information for the node whose SlicePattern is segment in the ops info config.
 *  @param   [in|out] node | slice info
 *  @return  SUCCESS or FAILED
 */
Status OpSetter::FillupSegmentSliceInfo(ge::OpDescPtr op_desc_ptr, OpCalcInfo &op_calc_info) {
  FE_LOGI("Not support this slice pattern yet.");
  return SUCCESS;
}

/*
 *  @ingroup fe
 *  @brief   Fill in the corresponding slice information for each node based on the 'SlicePattern' in the ops
 *           info config.
 *  @param   [in|out] node
 *  @return  SUCCESS or FAILED
 */
Status OpSetter::SetOpSlicePatternInfoByNode(ge::OpDescPtr op_desc_ptr, const OpKernelInfoPtr& op_kernel_info_ptr) {
  FE_LOGD("Start to set node[%s]'s slice info.", op_desc_ptr->GetName().c_str());
  FE_CHECK_NOTNULL(op_desc_ptr);
  // 1. check whether the slice_info already been set
  std::string op_calc_info_str;
  (void)ge::AttrUtils::GetStr(op_desc_ptr, OP_SLICE_INFO, op_calc_info_str);
  if (!op_calc_info_str.empty()) {
    FE_LOGD("node[%s] slice info %s has been set, no need to parse.",
            op_desc_ptr->GetName().c_str(), op_calc_info_str.c_str());
    return SUCCESS;
  }
  string op_name = op_desc_ptr->GetName();
  string op_type = op_desc_ptr->GetType();
  // 2. get the slice pattern from ops kernel info
  SlicePattern slice_pattern = op_kernel_info_ptr->GetOpSlicePattern();

  OpCalcInfo op_calc_info;
  if (!op_calc_info.Initialize()) {
    REPORT_FE_ERROR("[GraphOptJdgInst][SetOpInfo][SetOpSlicePtnInfo] op_calc_info initialize failed");
    return FAILED;
  }
  std::vector<AxisSplitMap> axis_split_maps;
  InputSplitInfo input_split_info;
  if (!input_split_info.Initialize()) {
    REPORT_FE_ERROR("[GraphOptJdgInst][SetOpInfo][SetOpSlicePtnInfo] input_split_info initialize failed");
    return FAILED;
  }
  OutputSplitInfo output_split_info;
  if (!output_split_info.Initialize()) {
    REPORT_FE_ERROR("[GraphOptJdgInst][SetOpInfo][SetOpSlicePtnInfo] output_split_info initialize failed");
    return FAILED;
  }

  auto slice_func_iter = split_info_map_.find(slice_pattern);
  if (slice_func_iter == split_info_map_.end()) {
    FE_LOGD("Not currently supported: op %s.slice_pattern:%d", op_desc_ptr->GetName().c_str(), slice_pattern);
    return SUCCESS;
  }
  // 3. set slice info for each supported slice pattern
  FillupSliceInfoPtr slice_func_ptr = slice_func_iter->second;
  FE_CHECK_NOTNULL(slice_func_ptr);
  Status status = (*slice_func_ptr)(op_desc_ptr, op_calc_info);
  if (status != SUCCESS) {
    FE_LOGD("Parse op slice pattern[%d] info for node[%s] not matched, do not set slice info.",
            slice_pattern, op_desc_ptr->GetName().c_str());
    return SUCCESS;
  }
  // set whether support l1fusion
  auto is_l1_node = find(LIST_OF_SUPPORT_L1_OP.begin(), LIST_OF_SUPPORT_L1_OP.end(), op_type);
  if (is_l1_node != LIST_OF_SUPPORT_L1_OP.end()) {
    FE_LOGD("node:%s[type:%s] support l1 fusion.", op_name.c_str(), op_type.c_str());
    op_calc_info.SetL1FusionEnable(L1FUSION_BASIC);
  }
  SetOpSliceInfoToJson(op_calc_info, op_calc_info_str);
  (void)ge::AttrUtils::SetStr(op_desc_ptr, OP_SLICE_INFO, op_calc_info_str);
  FE_LOGD("Set node[%s]'s slice info as %s", op_desc_ptr->GetName().c_str(), op_calc_info_str.c_str());
  return SUCCESS;
}
}  // namespace fe
